<?php

/*
 * Created on Dec 1, 2009
 * @author Christopher Sheldahl
 * 
 */

include_once("Bean.php");
include_once("LatLng.php");
include_once("Image.php");
include_once("/OmwptConfig.php");
include_once("WriteLrpUtil.php");
include_once("WriteQthUtil.php");

class splatPowerCalculation
{    
	/**
	 * run a splat power calculation, generating image in png format, and 
	 * other output files
	 * @param SplatPowerCommmandParam params
	 */
	 public function runSplatPowerCalculation($params ) 
	 { 
	 	$workingDirectory = $params->workingDirectory;
	 	$transmitterFileName = $params->transmitterFileName;
	 	$receiverHeight = $params->receiverHeight;
	 	$range = $params->range; 
	 	$imageFileName = $params->imageFileName;
	 	$erp = $params->erp;
	 	$alpha = $params->alpha; 		
	 	$splatPath = $params->splatPath;
	 	$convertPath = $params->convertPath;
	 	$latlng = $params->transLatLng;
	 	$freq = $params->freq;
		$climate = $params->climate;
		$polar = $params->polar;
		
	 	$lrpParam = new LrpParams($workingDirectory, $transmitterFileName, $freq, 
 						$climate, $polar, $erp);
 		WriteLrpUtil::writeFile($lrpParam);
	 	$qthParam = new QthParams($workingDirectory, $transmitterFileName, $receiverHeight, $latlng->lat, $latlng->lng);
	 	WriteQthUtil::writeFile($qthParam);
	 	
	 	$splatOutputString = "";
	 	//try {
	 	$splatOutputString = 
	 		splatPowerCalculation::runSplatPowerCalculationHelper(
	 			$workingDirectory, $splatPath, $transmitterFileName,
	 			$receiverHeight, $range, $imageFileName, $erp);

	 
	 /*	}
	 	catch( Exception $excep )
	 	{
	 		$splatOutputString = $excep->getMessage();
	 	}
	 	*/

	 	$dcfFile = $transmitterFileName . ".dcf";
	 	$ppmFileName = $imageFileName . ".ppm";
	 	$pngFileName = $imageFileName . ".png";
	 	splatPowerCalculation::processImage( $dcfFile, $convertPath, $ppmFileName, 
	 		$pngFileName, $alpha );
	 	
	 	$kmlFileName = $imageFileName . ".kml";
	 	$boundaryPoints = splatPowerCalculation::getLatLongBoundaries( $kmlFileName );
	 	$imageObject = new Image($pngFileName, $boundaryPoints[0], $boundaryPoints[1] );
	 	$result = new SplatOutput();
	 	$result->image = $imageObject;
	 	$result->splatOutputString = $splatOutputString;
	 	return $result;
	 }
	 
	/**
 	* 
 	* This function takes several parameters (described below) and it generates 
 	* and runs a splat power calculation.  The splat output is returned as a 
 	* string.  The splat output is also stored in the file transmitterFileName.log 
 	* in workingDirectory
	* Parameters:
 	* 1) $workingDirectory (string) will hold output files.  It should also hold 
 	* the LRP file if one is used (otherwise default values will be used), the 
 	* qth (transmitter) file, the elevation (.el) and azimuth (.az) radiation files, 
 	* and the contour color level (.dcf) file.
 	* 2) $splatPath (string) is the path to the splat exectuable.  It's best to 
 	* use fully qualified references.
 	* 3) transmitterFileName (string) is used to determine name of qth file 
 	* (for example if qth file is "foo.qth", then $transmitterFile should be 
 	* "foo"), and similarly the names of the elevation and azimuth radiation 
 	* pattern files ("foo.el" and "foo.az") and the contour color level file
 	* ("foo.dcf").
 	* 4) $receiverHeight is a nonnegative number for the height of the 
 	* receiver stations.
 	* 5) $range is a positive number in miles for the radius of the calculation 
 	* (centered at transmitter position given in qth file).
 	* 6) $ppmFileName is the (string) filename for the ppm format picture files 
 	* generated by splat.  If $ppmFileName is "foo" then the file "foo.ppm"
 	* will be placed in $workingDirectory.   
 	* The $ppmFileName (string) is also used to determine a name for the kml file 
 	* - which is useful because it contains the latitude and longitude limits that
 	* are needed to overlay the image in google Maps.
 	* 7) $erp (number) is the effective radiated power for the transmitter and 
 	* it will override any settings for the ERP in the LRP file.
 	**/
	private function runSplatPowerCalculationHelper($workingDirectory, $splatPath,
			$transmitterFileName, $receiverHeight, $range, 
			$ppmFileName, $erp) {
		//first make sure that the workingDirectory is a directory and that it 
		//can be read, written, and executed.
		$exceptionMessage = "";
		$errorOccurred = False;
		if ( ! is_dir($workingDirectory))
		{
			$exceptionMessage = $workingDirectory . " is not a directory.";
			$errorOccurred = True;
			throw new Exception($exceptionMessage);
		}
		//********
		if ( ! is_readable($workingDirectory) )
		{
			$exceptionMessage = $exceptionMessage . $workingDirectory . " is not readable. ";
			$errorOccurred = True;
		}
		if ( ! is_writable($workingDirectory) )
		{
			$exceptionMessage = $exceptionMessage . $workingDirectory . " is not writable. ";
			$errorOccurred = True;
		}
		/* Commented out by Tanner 12/7
		if ( ! is_executable($workingDirectory) )
		{
			$exceptionMessage = $exceptionMessage . $workingDirectory . " is not executable. ";
			$errorOccurred = True;
		}
		*/
	
		if ( $errorOccurred )
		{
			throw new Exception( $exceptionMessage );
		}
		//if we got here the workingDirectory is useable
		chdir($workingDirectory);
		//*****************
		//check splat path
		if ( ! is_file($splatPath) )
		{
			$exceptionMessage = $exceptionMessage . $splatPath . " is not a file. ";
			$errorOccured = True;
			throw new Exception($exceptionMessage);
		}
		if ( ! is_readable($splatPath) )
		{
			$exceptionMessage = $exceptionMessage . $splatPath . " is not readable. ";
			$errorOccurred = True;
		}
		/*
		if ( ! is_writable($splatPath) )
		{
			$exceptionMessage = $exceptionMessage . $splatPath . " is not writable. ";
			$errorOccurred = True;
		}
		*/
		if ( ! is_executable($splatPath) )
		{
			$exceptionMessage = $exceptionMessage . $splatPath . " is not executable. ";
			$errorOccurred = True;
		}
		if ( $errorOccurred )
		{
			throw new Exception( $exceptionMessage );
		}
		/****************
		 * if we got here workingDirectory and splatPath are both accessible
		 * splatPath may still not point to the executable
		 * check to make sure that at a minimum, the appropriate qth file exists
		 * in the current directory and is readable.  It may be the wrong format, though
		 * 	Next thing we do is check qthFileName, after that we start generating 
		 * the splat command
		 */
	
		$qthFileName = $transmitterFileName . ".qth";
		if ( ! is_file($qthFileName) )
		{
			$exceptionMessage = $exceptionMessage . $qthFileName . " is not a file. ";
			$errorOccured = True;
		}
		if ( ! is_readable($qthFileName) )
		{
			$exceptionMessage = $exceptionMessage . $splatPath . " is not readable. ";
			$errorOccurred = True;
		}
		if ( $errorOccurred )
		{
			throw new Exception( $exceptionMessage );
		}
		//*********************
	
		if ( $receiverHeight < 0 )
		{
			throw new Exception("Receiver height must be a non-negative number.");
		}
		if (  $range <= 0 )
		{
			throw new Exception("Range must be a positive number.");
		}
	
		if ( $erp < 0 )
		{
			throw new Exception("Effective radiative power (erp) must be non-negative number.");
		
		}
	
		//check for the existence of possible radiation pattern and color def (dcf) files
		if ( ! is_file( $transmitterFileName . ".el"))
		{
			throw new Exception( "elevation pattern file " . $transmitterFileName . ".el not found.");
		}
		if ( ! is_file( $transmitterFileName . ".az"))
		{
			throw new Exception( "azimuth pattern file " . $transmitterFileName . ".az not found.");
		}
		if ( ! is_file( $transmitterFileName . ".dcf"))
		{
			throw new Exception( "color definition file " . $transmitterFileName . ".dcf not found.");
		}	
	
	
		 
		//$command = '/usr/local/bin/splat -erp 30000 -t wnju-dt -L 30.0 -dbm -kml -ano wjnu-dt.ano -R 5 -ngs -o white_map';
		
		$anoFileName = $transmitterFileName; // . ".ano"; -Commented out by Tanner 
		//create the splat command string
		$command  = $splatPath . " -erp " . $erp . " -t " . $transmitterFileName;
		$command = $command . " -L " . $receiverHeight . " -dbm -kml ";
		$command = $command . " -ano " . $anoFileName . ".ano ";
		$command = $command ." -R " . $range;
		$command = $command . " -d " . OmwptConfig::sdfDirectory;
		$command = $command . " -ngs -o " . $ppmFileName . ".ppm";
		$command = $command . " > " . $transmitterFileName . ".log"; // Removed & from " >& "
		// Tanner's Test
//		throw new Exception( "The command: " . $command);
		set_time_limit(500);
		$retval = 0;
   	 	$last_line = system($command, $retval); 
   	 	
    	//echo $last_line;
    	if ( $retval == 255 )
		{
			throw new Exception( "Unknown error when invoking Splat!.");
		}
		
		$logLines = file($transmitterFileName . ".log");
		$logString = "";
		foreach($logLines as $line)
		{
			$logString = $logString . $line;
		}
		 
     	return $logString;
    	
	}	//close function
	
	/**
	 * returns a 1D array with two elements, both of them LatLng objects.
	 * The first element in the array is the NorthEast boundary point,
	 * the second is the SouthWest boundary point.  This is meant to be used 
	 * with Google maps overlays.
	 * The values are read from a kml file generated by splat ($kmlFileName - a
	 * string)
	 */
	public function getLatLongBoundaries($kmlFileName) {
		$file = fopen($kmlFileName,"r") or die("Can't open file.");
		$lookingForInfo = True;
		while(! feof($file) && $lookingForInfo )
		{
			$curr_line = fgets($file);
			$curr_line = trim( $curr_line );
			if (strcmp($curr_line, "<LatLonBox>") == 0)
			{
				$lookingForInfo = False;
		 
				//get north value
				$northLine = fgets($file);
				$northLine = trim( $northLine ); //trim whitespace
				$northLineNumberString = trim($northLine, "<north>/");
				$northFloat = floatVal($northLineNumberString);
				//echo "northFloat: " . $northFloat . "\n";
				//get south value
				$southLine = fgets($file);
				$southLine = trim( $southLine ); //trim whitespace
				$southLineNumberString = trim($southLine, "<south>/");
				$southFloat = floatVal($southLineNumberString);
				//echo "southFloat: " . $southFloat . "\n";
				//get east value
				$eastLine = fgets($file);
				$eastLine = trim( $eastLine ); //trim whitespace
				$eastLineNumberString = trim($eastLine, "<east>/");
				$eastFloat = floatVal($eastLineNumberString);
				//echo "eastFloat: " . $eastFloat . "\n";
				//get west value
				$westLine = fgets($file);
				$westLine = trim( $westLine ); //trim whitespace
				$westLineNumberString = trim($westLine, "<west>/");
				$westFloat = floatVal($westLineNumberString);
			 
				$northEast = new LatLng( $northFloat, $eastFloat);		 
				$southWest = new LatLng($southFloat, $westFloat);
				$boundaryArray = array();
				$boundaryArray[0] = $northEast;
				$boundaryArray[1] = $southWest;
				//print_r($boundaryArray);
				return $boundaryArray;
			}
  		//echo "<br />";
	}	//close while

	fclose($file);
	}
	
	/**
	 * do post processing on an image file generated by splat.  For best results,
	 * the input file name ($inFile) should have been generated with topography shown in
	 * white (-ngs flag in splat command).  The input file is turned into a partially transparent
	 * png file ($outFile), suitable for use in google maps overlays.  The colors definitions are read
	 * from $dcfColorFile, which should be the same file that was used in the splat command that
	 * generated the ppm file.  The degree of transparency is determined by the float $alpha which
	 * should be in the range 0.0<=$alpha<=1.0.  An $alpha of 0.0 gives a fully transparent image,
	 * and $alpha of 1.0 gives a fully opaque image.  The image conversions are done using the
	 * convert utility of the ImageMagick package - $convertExec is the path for the convert utility.\
	 * $dcfColorFile : string
	 * $convertExec : string
	 * $inFile : string
	 * $outFile : string
	 * $alpha : float in range 0.0<=$alpha<=1.0
	 */
	private function processImage( $dcfColorFile, $convertExec, $inFile, $outFile, $alpha)
	{
		//echo $dcfColorFile;
		if (($alpha < 0.0) or ($alpha > 1.0))
		{
			$message = "alpha value for transparency should in"
						. " range 0.0<= alpha <=1.0";
			throw new Exception($message);
		}
		echo "<br>Processing image: ";
		$file = fopen($dcfColorFile,"r") or die("Can't open file.");
		$firstStatement = $convertExec . ' -transparent "#FFFFFF" '  . $inFile . " " . $outFile;
		//throw new Exception($firstStatement);
		$convertStatements = array( 0 => $firstStatement);
		while(! feof($file) )
		{
			$currLine = fgets($file);
	
			if ($currLine[0] == ';')
			{
				continue;	//skip comment
			}
			//else get color info and generate next ImageMagick convert statement
			$tokens = preg_split("/[\s]+/", $currLine);
			//print_r($tokens);
			$oldLength = count($tokens);
			//remove empty strings and renumber
			$cleanTokenArray = array();
			for ( $i = 0; $i < $oldLength; $i++)
			{
				if ( strcmp($tokens[$i], "") == 0 )
				{
					//echo "tokens[ " . $i . "] is the empty string\n";
					continue;
				}
				$cleanTokenArray[] = $tokens[$i];
			}
			//print_r($cleanTokenArray);
			$newLength = count($cleanTokenArray);
			if ($newLength > 0 && $newLength != 4 )
			{
				die("Line in dcf file is incorrect.");
			}
			if ( $newLength == 4 )
			{
				$cleanTokenArray[1] = trim($cleanTokenArray[1], ",");
				$cleanTokenArray[2] = trim($cleanTokenArray[2], ",");
				$red = intVal($cleanTokenArray[1]);
				$green = intVal($cleanTokenArray[2]);
				$blue = intVal($cleanTokenArray[3]);
				//echo $red . " " . $green . " " . $blue . "\n";
	
				$nextCommand = $convertExec . " " . $outFile . ' -alpha set -channel RGBA';
				$nextCommand = $nextCommand . ' -fill "rgba(' . $red . "," . $green . "," . $blue . "," . $alpha . ')" ';
				$nextCommand = $nextCommand . '-opaque "rgb(' . $red .  "," . $green . "," . $blue . ')"' ;
				$nextCommand = $nextCommand . " " . $outFile;
				//throw new Exception($nextCommand);
				//echo $nextCommand . "\n";
				$convertStatements[] = $nextCommand;
				//convert transparent_map.png -alpha set -channel RGBA -fill "rgba(0,196,196,0.5)" -opaque "rgb(0,196,196)" test.png
			}
		}	//close while
		//print_r($convertStatements);
		//run statements
		foreach ($convertStatements as $currStatement)
		{
			//echo "Running $currStatement.\n";
			echo "*";
			exec( $currStatement );
		}
		fclose($file);
		
	}	//close function
}		//close class
//*****MAIN********
/*
$params = new SplatPowerCommandParams();
$params->workingDirectory = "/Users/sheldahl/splat-1.3.0";
$params->splatPath = "/usr/local/bin/splat";
$params->transmitterFileName = "wnju-dt";
$params->receiverHeight = 30;
$params->range = 5;
$params->imageFileName = "testImage";
$params->erp = 6500000;
$params->alpha = 0.5;
$params->convertPath = "/usr/local/bin/convert";
$output = splatPowerCalculation::runSplatPowerCalculation($params );
$message = $output->splatOutputString;
echo "\nmessage = " . $message;
$image = $output->image;
echo "\nimagePath = " . $image->getImagePath;
echo "<br>";
$upper = $image->getUpper();
$lower = $image->getLower();
echo "\nupperLat = " . $upper->lat;
echo "<br>";
echo "\nuperLng = " . $upper->lng;
echo "<br>";
echo "\nlowerLat = " . $lower->lat;
echo "<br>";
echo "\nlowerLng = " . $lower->lng;
echo "<br>";
echo "\n";
*/

?>
